package com.tengfei.main.plan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tengfei.common.constant.UserConstants;
import com.tengfei.common.core.domain.PageQuery;
import com.tengfei.common.core.page.TableDataInfo;
import com.tengfei.common.exception.ServiceException;
import com.tengfei.common.helper.DataBaseHelper;
import com.tengfei.common.utils.StringUtils;
import com.tengfei.main.course.domain.Course;
import com.tengfei.main.course.domain.vo.CourseVo;
import com.tengfei.main.course.mapper.CourseMapper;
import com.tengfei.main.plan.domain.Plan;
import com.tengfei.main.plan.domain.PlanCourses;
import com.tengfei.main.plan.domain.PlanUsers;
import com.tengfei.main.plan.domain.bo.PlanBo;
import com.tengfei.main.plan.domain.bo.PlanCoursesBo;
import com.tengfei.main.plan.domain.bo.PlanUsersBo;
import com.tengfei.main.plan.domain.vo.PlanCoursesVo;
import com.tengfei.main.plan.domain.vo.PlanSimpleVo;
import com.tengfei.main.plan.domain.vo.PlanUsersVo;
import com.tengfei.main.plan.domain.vo.PlanVo;
import com.tengfei.main.plan.mapper.PlanCoursesMapper;
import com.tengfei.main.plan.mapper.PlanMapper;
import com.tengfei.main.plan.mapper.PlanUsersMapper;
import com.tengfei.main.plan.service.IPlanService;
import com.tengfei.main.system.domain.SysDept;
import com.tengfei.main.system.domain.SysUser;
import com.tengfei.main.system.mapper.SysDeptMapper;
import com.tengfei.main.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 学习计划Service业务层处理
 *
 * @author tengfei
 * @date 2022-08-01
 */
@Service
public class PlanServiceImpl implements IPlanService {

    @Resource
    private PlanMapper baseMapper;
    @Resource
    private PlanCoursesMapper planCourseMapper;
    @Resource
    private PlanUsersMapper planUserMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private SysUserMapper userMapper;
    @Resource
    private SysDeptMapper deptMapper;


    /**
     * 查询学习计划
     */
    @Override
    public PlanVo queryById(Long planId) {
        return baseMapper.selectVoById(planId);
    }

    /**
     * 查询学习计划列表
     */
    @Override
    public TableDataInfo<PlanVo> queryPageList(PlanBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Plan> lqw = buildQueryWrapper(bo);
        Page<PlanVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    private LambdaQueryWrapper<Plan> buildQueryWrapper(PlanBo bo) {
        LambdaQueryWrapper<Plan> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getPlanName()), Plan::getPlanName, bo.getPlanName());
        lqw.eq(bo.getPlanToStart() != null, Plan::getPlanToStart, bo.getPlanToStart());
        lqw.orderByDesc(Plan::getUpdateTime);
        return lqw;
    }

    /**
     * 查询简易学习计划列表
     */
    @Override
    public List<PlanSimpleVo> querySimpleList(String planName) {
        List<Plan> plans = baseMapper.selectList(new LambdaQueryWrapper<Plan>()
                .like(ObjectUtil.isNotNull(planName), Plan::getPlanName, planName)
                .orderByDesc(Plan::getUpdateTime));
        List<PlanSimpleVo> planSimpleVos = BeanUtil.copyToList(plans, PlanSimpleVo.class);
        return planSimpleVos;
    }

    /**
     * 新增学习计划
     */
    @Override
    public Boolean insertByBo(PlanBo bo) {
        validEntityBeforeSave(bo);
        Plan add = BeanUtil.toBean(bo, Plan.class);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setPlanId(add.getPlanId());
        }
        return flag;
    }

    /**
     * 修改学习计划
     */
    @Override
    public Boolean updateByBo(PlanBo bo) {
        validEntityBeforeSave(bo);
        Plan update = BeanUtil.toBean(bo, Plan.class);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PlanBo bo) {
        // 学习计划结束时间必须大于开始时间
        if (bo.getPlanEndTime().getTime() <= bo.getPlanStartTime().getTime()) {
            throw new ServiceException("学习计划结束时间必须大于开始时间");
        }
        // 计划最低完成度必须在0~100以内
        if (bo.getPlanMinDegree() < 0 || bo.getPlanMinDegree() > 100) {
            throw new ServiceException("计划最低完成度必须在0~100以内");
        }
    }

    /**
     * 批量删除学习计划
     */
    @Transactional
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        // 未到计划结束时间，计划不可删除
        ids.forEach(id -> {
            Plan plan = baseMapper.selectById(id);
            if (new Date().getTime() < plan.getPlanEndTime().getTime()) {
                throw new ServiceException("课程:" + plan.getPlanName() + ",未到课程计划结束时间，计划不可删除");
            }
            // TODO 删除中间表内容
            // 删除计划课程表中间内容
            planCourseMapper.delete(new QueryWrapper<PlanCourses>()
                    .eq("plan_id", id));
            // 删除计划用户表中间内容
            planUserMapper.delete(new QueryWrapper<PlanUsers>()
                    .eq("plan_id", id));
            baseMapper.deleteById(id);
        });
        return true;
    }

    /**
     * 开启学习计划
     */
    @Override
    public Boolean openPlan(Long id) {
        if (ObjectUtil.isNull(id)) {
            throw new ServiceException("id为空");
        }
        Plan plan = new Plan();
        plan.setPlanId(id);
        plan.setPlanToStart(1);
        return baseMapper.updateById(plan) > 0;
    }

    /**
     * 关闭学习计划
     */
    @Override
    public Boolean closePlan(Long id) {
        if (ObjectUtil.isNull(id)) {
            throw new ServiceException("id为空");
        }
        Plan plan = new Plan();
        plan.setPlanId(id);
        plan.setPlanToStart(0);
        return baseMapper.updateById(plan) > 0;
    }

    /**
     * 新增学习计划课程
     */
    @Transactional
    @Override
    public Boolean insertPlanCourseByBos(List<PlanCoursesBo> bos) {
        // 判断是否符合逻辑，课程的开始时间小于计划开始时间，课程结束时间大于计划结束时间
        Plan plan = baseMapper.selectById(bos.get(0).getPlanId());
        bos.forEach(bo -> {
            Course course = courseMapper.selectById(bo.getCourseId());
            if (course.getCourseBeginDate().getTime() < plan.getPlanStartTime().getTime() ||
                    course.getCourseEndDate().getTime() > plan.getPlanEndTime().getTime()) {
                throw new ServiceException("课程：<<" + course.getCourseTitle() + ">>的时间应该在计划任务时间范围之内");
            }
            planCourseMapper.insert(BeanUtil.copyProperties(bo, PlanCourses.class));
        });
        return true;
    }

    /**
     * 新增学习计划用户
     */
    @Transactional
    @Override
    public Boolean insertPlanUserByBos(List<PlanUsersBo> bos) {
        // TODO 待判断条件
        List<PlanUsers> planUsers = BeanUtil.copyToList(bos, PlanUsers.class);
        return planUserMapper.insertBatch(planUsers);
    }

    /**
     * 删除学习计划课程
     */
    @Transactional
    @Override
    public Boolean deletePlanCourseByIds(List<Long> ids) {
        // TODO 待判断条件
        return planCourseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 删除学习计划用户
     */
    @Override
    public Boolean deletePlanUserByIds(List<Long> ids) {
        // TODO 待判断条件
        return planUserMapper.deleteBatchIds(ids) > 0;
    }


    /**
     * 查询学习计划课程列表
     */
    @Override
    public List<PlanCoursesVo> queryPlanCourseList(Long id) {
        List<PlanCourses> planCourses = planCourseMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                .eq(PlanCourses::getPlanId, id));
        List<PlanCoursesVo> planCoursesVos = new ArrayList<>();
        planCourses.forEach(planCourse -> {
            CourseVo courseVo = courseMapper.selectVoOne(new LambdaQueryWrapper<Course>()
                    .eq(Course::getCourseId, planCourse.getCourseId())
                    .orderByDesc(Course::getUpdateTime));
            PlanCoursesVo planCoursesVo = BeanUtil.copyProperties(courseVo, PlanCoursesVo.class);
            planCoursesVo.setId(planCourse.getId());
            planCoursesVo.setPlanId(id);
            planCoursesVos.add(planCoursesVo);
        });
        return planCoursesVos;
    }

    /**
     * 查询学习计划未绑定课程列表
     */
    @Override
    public TableDataInfo<CourseVo> queryPlanCourseListUnBind(Long planId, String courseName, PageQuery pageQuery) {
        IPage<CourseVo> courseVoIPage = courseMapper.selectVoPage(pageQuery.build(), new LambdaQueryWrapper<Course>()
                .like(ObjectUtil.isNotNull(courseName), Course::getCourseTitle, courseName)
                .orderByDesc(Course::getUpdateTime)
                .notInSql(Course::getCourseId, "select course_id from sp_plan_course where plan_id=" + planId));
        return TableDataInfo.build(courseVoIPage);
    }

    /**
     * 查询学习计划用户列表
     */
    @Override
    public TableDataInfo<PlanUsersVo> queryPlanUserList(PlanUsersBo planUsersBo, PageQuery pageQuery) {
        Page<PlanUsersVo> page = baseMapper.selectPlanUserList(pageQuery.build(), this.buildQueryWrapperUser(planUsersBo, true));
        return TableDataInfo.build(page);
    }

    /**
     * 查询学习计划未绑定用户列表
     */
    @Override
    public TableDataInfo<PlanUsersVo> queryPlanUserListUnBind(PlanUsersBo planUsersBo, PageQuery pageQuery) {
        Page<PlanUsersVo> page = baseMapper.selectPlanUserListUnBind(pageQuery.build(), this.buildQueryWrapperUser(planUsersBo, false), planUsersBo.getPlanId());
        return TableDataInfo.build(page);
    }

    private Wrapper<SysUser> buildQueryWrapperUser(PlanUsersBo planUsersBo, boolean isBinding) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper
                .apply(isBinding, "s.plan_id=" + planUsersBo.getPlanId())
                .eq("u.show_status", UserConstants.USER_NORMAL)
                .eq("u.status", UserConstants.USER_NORMAL)
                .like(StringUtils.isNotBlank(planUsersBo.getName()), "u.name", planUsersBo.getName())
                .and(ObjectUtil.isNotNull(planUsersBo.getDeptId()), w -> {
                    List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
                            .select(SysDept::getDeptId)
                            .apply(DataBaseHelper.findInSet(planUsersBo.getDeptId(), "ancestors")));
                    List<Long> ids = deptList.stream().map(SysDept::getDeptId).collect(Collectors.toList());
                    ids.add(planUsersBo.getDeptId());
                    w.in("u.dept_id", ids);
                });
        return wrapper;
    }


}
